﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text.RegularExpressions;

namespace Axial
{
	public static class ConditionHelper
	{
		public static string CreateConditionString(Stack stack, OpCode code)
		{
			var a = stack.Pop() ?? "null";
			if (code == OpCodes.Ceq || code == OpCodes.Cgt || code == OpCodes.Cgt_Un || code == OpCodes.Clt || code == OpCodes.Clt_Un)
				return a.ToString();
			if (code == OpCodes.Br || code == OpCodes.Br_S)
				return a.ToString();
			if (code == OpCodes.Brtrue || code == OpCodes.Brtrue_S)
				return a.ToString();
			if (code == OpCodes.Brfalse || code == OpCodes.Brfalse_S)
				return "!" + a;

			var b = stack.Pop() ?? "null";
			if (code == OpCodes.Bne_Un_S)
				return b + " != " + a;
			if (code == OpCodes.Beq_S)
				return b + " == " + a;
			if (code == OpCodes.Bgt_S || code == OpCodes.Bgt_Un_S)
				return b + " > " + a;
			if (code == OpCodes.Bge_S || code == OpCodes.Bge_Un_S)
				return b + " >= " + a;
			if (code == OpCodes.Blt_S || code == OpCodes.Blt_Un_S)
				return b + " < " + a;
			if (code == OpCodes.Ble_S || code == OpCodes.Ble_Un_S)
				return b + " <= " + a;
			throw new NotImplementedException("can't create condition from a " + code.Name + " OpCode");
		}

		public static string CompactCondition(string condition)
		{
			Dictionary<Regex, string> replacements = new Dictionary<Regex, string> {
				{ new Regex(@"^(.+) == (.+) == 0$"), "$1 != $2" },
				{ new Regex(@"^(.+) < (.+) == 0$"), "$1 >= $2" },
				{ new Regex(@"^(.+) > (.+) == 0$"), "$1 <= $2" }
			};
			foreach (KeyValuePair<Regex, string> pair in replacements)
				if (pair.Key.IsMatch(condition))
					return pair.Key.Replace(condition, pair.Value);
			return condition;
		}

		public static string InvertCondition(string condition)
		{
			Dictionary<Regex, string> replacements = new Dictionary<Regex, string> {
				{ new Regex(@"^(.+) (\p{Sm}+) (.+) == 0$"), "$1 $2 $3" },
				{ new Regex(@"^(.+) == 0$"), "$1" },
				{ new Regex(@"^(.+) == (.+)$"), "$1 != $2" },
				{ new Regex(@"^(.+) != (.+)$"), "$1 == $2" },
				{ new Regex(@"^(.+) < (.+)$"), "$1 >= $2" },
				{ new Regex(@"^(.+) <= (.+)$"), "$1 > $2" },
				{ new Regex(@"^(.+) > (.+)$"), "$1 <= $2" },
				{ new Regex(@"^(.+) >= (.+)$"), "$1 < $2" }
			};
			foreach (KeyValuePair<Regex, string> pair in replacements)
				if (pair.Key.IsMatch(condition))
					return pair.Key.Replace(condition, pair.Value);
			return "!" + condition;
		}

		internal static string InvertConditionEnd(string condition)
		{
			// important that patterns sorted by length grouped by first character
			string[] patterns = { "==", "!=", "<=", "<", ">=", ">" };
			string[] opposite = { "!=", "==", ">", ">=", "<", "<=" };
			int? atIndex = null;
			int? patternIndex = null;
			for (int i = 0; i < patterns.Length; i++)
			{
				string pattern = patterns[i];
				int lastIndex = condition.LastIndexOf(pattern);
				if (atIndex == null || lastIndex > atIndex)
				{
					atIndex = lastIndex;
					patternIndex = i;
				}
			}
			if (atIndex != null)
				return condition.Remove(atIndex.Value, patterns[patternIndex.Value].Length)
								.Insert(atIndex.Value, opposite[patternIndex.Value]);
			return "!" + condition;
		}

		public static string CombineConditions(IEnumerable<ConditionStatement> conditions, int trueOffset)
		{
			string result = "";
			foreach (var condition in conditions)
				if (condition.FlowTarget == trueOffset)
					result += condition.Condition + " || ";
				else
					result += condition.OppositeCondition + " && ";
			return result.Substring(0, result.Length - 4);
		}
	}
}
